import os
import shutil
import paramiko
from datetime import datetime
from typing import List

class RemoteConnectionError(Exception):
    """自定义异常类，用于远程连接相关错误"""
    pass

class BackupError(Exception):
    """自定义异常类，用于备份操作错误"""
    pass

def list_remote_directory(
    host: str,
    username: str,
    password: str,
    remote_path: str = '/root/'
) -> List[str]:
    """
    使用SFTP协议安全地列出远程目录内容
    
    参数:
        host: 远程主机地址
        username: 登录用户名
        password: 登录密码
        remote_path: 远程目录路径（默认：/root/）
    
    返回:
        排序后的目录条目列表
    
    异常:
        RemoteConnectionError: 连接或认证失败时抛出
    """
    try:
        with paramiko.Transport((host, 22)) as transport:
            transport.connect(username=username, password=password)
            sftp = paramiko.SFTPClient.from_transport(transport)
            
            # 获取目录列表并排序
            entries = sftp.listdir_attr(remote_path)
            sorted_entries = sorted(
                [entry.filename for entry in entries],
                key=lambda x: os.path.getmtime(os.path.join(remote_path, x))
            )
            
            return sorted_entries
            
    except paramiko.AuthenticationException:
        raise RemoteConnectionError("Authentication failed")
    except paramiko.SSHException as e:
        raise RemoteConnectionError(f"SSH connection error: {str(e)}")
    finally:
        sftp.close() if 'sftp' in locals() else None

def backup_folder(
    src: str,
    dest: str,
    max_backups: int = 5
) -> str:
    """
    增强版文件夹备份功能，支持自动清理旧备份
    
    参数:
        src: 源文件夹路径
        dest: 备份存储目录
        max_backups: 最大备份数量（默认保留5个）
    
    返回:
        生成的备份路径
    
    异常:
        BackupError: 备份过程中发生错误时抛出
    """
    try:
        # 验证源路径
        if not os.path.isdir(src):
            raise BackupError(f"Source path invalid: {src}")

        # 创建带时间戳的备份目录
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        backup_dir = os.path.join(dest, f"backup_{timestamp}")
        shutil.copytree(src, backup_dir)

        # 清理旧备份（保留最近max_backups个）
        backups = sorted(
            [d for d in os.listdir(dest) if d.startswith('backup_')],
            reverse=True
        )
        for old_backup in backups[max_backups:]:
            shutil.rmtree(os.path.join(dest, old_backup))

        return backup_dir

    except Exception as e:
        raise BackupError(f"Backup failed: {str(e)}")

def main():
    """主程序流程控制"""
    # 配置参数
    REMOTE_CONFIG = {
        "host": "172.40.0.88",
        "username": "root",
        "password": "123456",
        "remote_path": "/root/hesu/"
    }
    
    BACKUP_CONFIG = {
        "src": r"D:\python_code",
        "dest": r"D:\backup_folder"
    }

    try:
        # 列出远程目录
        print("Listing remote directory...")
        remote_files = list_remote_directory(**REMOTE_CONFIG)
        print("Remote files:", remote_files)

        # 执行备份
        print("\nCreating backup...")
        backup_path = backup_folder(**BACKUP_CONFIG)
        print(f"Backup created at: {backup_path}")

    except RemoteConnectionError as e:
        print(f"[Connection Error] {str(e)}")
    except BackupError as e:
        print(f"[Backup Error] {str(e)}")
    except Exception as e:
        print(f"[Unexpected Error] {str(e)}")

if __name__ == "__main__":
    main()